package com.zhangfei.config;


import com.zhangfei.vote.CustomAccessDecisionVoter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.vote.AffirmativeBased;
import org.springframework.security.access.vote.UnanimousBased;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.expression.WebExpressionVoter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.List;


@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {



    @Autowired
    public DataSource dataSource;

    public PersistentTokenRepository persistentTokenRepository(){
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        return jdbcTokenRepository;
    }


    @Autowired
    private UserDetailsService myUserDetailsServiceImpl;


    @Autowired
    private CustomAccessDecisionVoter customAccessDecisionVoter;

    @Bean
    public PasswordEncoder passwordEncoder() {
//        return NoOpPasswordEncoder.getInstance();
        return new BCryptPasswordEncoder();
    }


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //可以配置，不配置，也会自动解析到
//        auth.userDetailsService(userDetailsService);

        //多个userDetailsServiceImpl,需要关闭一个，可以通过这个方式指定某一个
        auth.userDetailsService(myUserDetailsServiceImpl);

        //内存方式，存储用户数据
//        auth.inMemoryAuthentication()
//                .withUser("admin")
//                .password(passwordEncoder().encode("123456"))
//                .authorities("amdin");


    }


    /**
     * 自定义登录逻辑
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()//表达登录
                .loginPage("/login.html")//自定义登录的页面地址
                .loginProcessingUrl("/user/login")//登录处理逻辑地址
                .defaultSuccessUrl("/main.html")//登录成功后的页面地址
                .failureUrl("/error.html")//登录失败后的页面地址
                .permitAll() // 允许所有用户访问登录页面和登录处理URL

           //自定义处理类：成功和失败的重定向，逻辑处理
//            .successHandler(new MyAuthenticationSuccessHandler("/main.html"))
//            .failureHandler(new MyAuthenticationFailHandler("/error.html"))
//        .successForwardUrl("/login/tomain")//重定向,失败了，暂时不知道原因
//        .failureForwardUrl("/login/toerror")//重定向,失败了，暂时不知道原因
        ;


        // 会话管理
        http.sessionManagement()
                .invalidSessionUrl("/login.html"); // 会话无效时重定向到登录页面

        //session创建逻辑
        http.sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);

        //记住我
//        http.rememberMe()
//                .tokenRepository(persistentTokenRepository())//设置持久化仓库
//                .tokenValiditySeconds(3600) //超时时间,单位s 默认两周
//                .userDetailsService(userServiceImpl);  //设置自定义登录逻辑

        //退出页面
        http.logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/login.html");

        //session超时之后，可以通过Spring Security 设置跳转的路径。
//        http.sessionManagement()
//                .invalidSessionUrl("/session/invalid")
//                .maximumSessions(1)
//                .expiredSessionStrategy(new MyExpiredSessionStrategy())
//                .maxSessionsPreventsLogin(true)//当达到maximumSessions设置的最大会话个数时阻止登录。
//        ;


        // 授权
        http.authorizeRequests()
                .antMatchers("/login.html","/user/login","/login/toerror","/main.html","/error.html","/session/invalid","/register")
                .permitAll()

//设置权限
                .antMatchers("/company").hasAuthority("company")
                .antMatchers("/user").hasAuthority("user")

//设置角色
                .antMatchers("/car").hasRole("car")
                .antMatchers("/mobile").hasRole("mobile")


                .anyRequest().authenticated()
        .and().csrf().disable(); //跨站点访问攻击



        //设置授权决策
//        http.authorizeRequests().accessDecisionManager(accessDecisionManager());

    }

    /**
     * 自定义授权决策器
     * @return
     */
//    @Bean
//    public AccessDecisionManager accessDecisionManager() {
//        List<AccessDecisionVoter<?>> decisionVoters = new ArrayList<>();
//        //这个是默认的授权决策器
//        decisionVoters.add(new WebExpressionVoter());
//        decisionVoters.add(customAccessDecisionVoter); // 添加你的自定义Voter
//
//        // ... 添加其他Voter ...
//        return new UnanimousBased(decisionVoters); // 使用AffirmativeBased或其他策略
//    }


}
